import SpawnController from '@/modules/structures/spawn'
import { AdaptionJudgeFn, CreepRoles } from '@/modules/structures/spawn/types'
import { BodyPartArrayType } from '@/utils/common'
import { CONTROLLER_ENERGY } from '@/utils/constants'
import { HarvesterData, SourceInfo } from './types'
import { goTo } from '@/modules/move'
import PCTaskManager from '../../pc'
import { isOfficialShard } from '@/ayaka'

/**
 * harvester 工作函数，统筹所有 harvester 的工作
 * 1. 找寻 container 或者 link，没有的话找 site，再没有就不管了，直接挖（自己不会摆 site，而是等待自动布局或者手动布局摆）
 */
export const harvesterWork = function (harvesters: Creep[], sourceId: Id<Source>, sourceInfo: SourceInfo) {
    const creeps = harvesters.filter((creep) => !creep.spawning)
    if (!creeps.length) return

    creeps.forEach((creep) => {
        getWorking(creep)
        setSourceDanger(creep, sourceInfo)

        delete creep.memory.stand
        if (creep.memory.slack) return

        const source = Game.getObjectById(sourceId) as Source

        // 尝试 pc 增产
        PCTaskManager.autoAddTask(source.room as MyRoom, PWR_REGEN_SOURCE, source, 10, 20)

        if (creep.memory.working) {
            const data = creep.memory.data as HarvesterData
            if (!data.aroundStructIds) {
                const structures = creep.pos.findInRange(FIND_STRUCTURES, 1, {
                    filter: (s) =>
                        ([STRUCTURE_TOWER, STRUCTURE_SPAWN, STRUCTURE_EXTENSION] as StructureConstant[]).includes(
                            s.structureType,
                        ),
                }) as (StructureExtension | StructureTower | StructureSpawn)[]
                data.aroundStructIds = structures.map((s) => s.id)
            }

            for (const id of data.aroundStructIds) {
                const struct = Game.getObjectById(id)
                if (struct && creep.pos.isNearTo(struct) && struct.store.getFreeCapacity(RESOURCE_ENERGY) > 0) {
                    const result = creep.transfer(struct, RESOURCE_ENERGY)
                    // 每 t 只能执行一次
                    if (result === OK) return
                }
            }

            let target: StructureLink | StructureContainer | null = null

            for (const type of ['linkId', 'containerId'] as const) {
                if (sourceInfo[type]) {
                    target = Game.getObjectById(sourceInfo[type]!) as StructureLink | StructureContainer
                    if (!target) {
                        delete sourceInfo[type]
                        continue
                    }
                    if (type === 'linkId' && !target.room.memory.centerLinkId) {
                        target = null
                    } else {
                        break
                    }
                }
            }

            if (target) {
                if (creep.pos.getRangeTo(target) > 1) {
                    goTo(creep, target.pos)
                }

                if (target.hits < target.hitsMax * 0.9) {
                    creep.repair(target)
                    return
                }

                if (target instanceof StructureContainer) {
                    if (target.store.getFreeCapacity() < creep.store['energy']) {
                        creep.memory.slack = 5
                        return
                    }

                    if (!creep.pos.isEqualTo(target)) transferEnergy(creep, target)
                    creep.harvest(source)
                } else {
                    if (target.store.getFreeCapacity('energy') <= 0) {
                        if (!target.cooldown) {
                            const centerLink = Game.getObjectById(target.room.memory.centerLinkId!)
                            if (centerLink) {
                                if (centerLink.store['energy'] <= 0) {
                                    // sourceLink 转移能量到 centerLink
                                    const result = target.transferEnergy(centerLink)
                                    if (result === OK) {
                                        transferEnergy(creep, target)
                                    }
                                } else {
                                    creep.memory.slack = 5
                                }
                            } else {
                                delete target.room.memory.centerLinkId
                            }
                        } else {
                            creep.memory.slack = target.cooldown
                        }
                    } else {
                        transferEnergy(creep, target)
                    }
                }
                return
            }

            // 没有 container 或者 link 的话就找 site
            if (!creep.memory.targetId) {
                const site = creep.pos.findInRange(FIND_CONSTRUCTION_SITES, 3, {
                    filter: (s) => ['container', 'link'].includes(s.structureType),
                })[0]
                if (site) {
                    creep.memory.targetId = site.id
                } else {
                    creep.memory.slack = 11
                }
            } else {
                const site = Game.getObjectById(creep.memory.targetId as Id<ConstructionSite>)
                if (!site) {
                    delete creep.memory.targetId
                } else if (creep.pos.getRangeTo(site) <= 3) {
                    creep.build(site)
                } else {
                    goTo(creep, site.pos, { range: 3 })
                }
            }
        } else {
            // 只有一个爬时移动到 container 上
            if (sourceInfo.containerId && creeps.length === 1) {
                const container = Game.getObjectById(sourceInfo.containerId) as StructureContainer
                if (container) {
                    if (!creep.pos.isEqualTo(container.pos)) {
                        goTo(creep, container.pos, { range: 0 })
                        return
                    }
                } else {
                    delete sourceInfo.containerId
                }
            }

            // 记录下旅行时间
            if (!creep.memory.travelTime && creep.pos.getRangeTo(source.pos) <= 3) {
                creep.memory.travelTime = 1500 - (creep.ticksToLive || 0)
            }

            if (creep.pos.isNearTo(source)) {
                if (source.energy > 0) {
                    creep.harvest(source)
                    creep.memory.stand = true
                    // 避免 source 过早采干
                    if (!sourceInfo.linkId && source.energy < source.ticksToRegeneration * 10 - 200) {
                        creep.memory.slack = 13
                    }
                } else {
                    creep.memory.slack = Math.max(Math.floor(source.ticksToRegeneration / 3), 3)
                }
            } else {
                goTo(creep, source.pos)
            }
        }
    })
}

/**
 * 获取工作状态
 */
function getWorking(creep: Creep) {
    if (creep.memory.working && creep.store[RESOURCE_ENERGY] === 0) {
        creep.memory.working = false
    }
    if (
        !creep.memory.working &&
        creep.store.getCapacity() - creep.store[RESOURCE_ENERGY] < (creep.memory.bodyParts?.work || 5) * 2
    ) {
        creep.memory.working = true
    }
}

/**
 * 转移能量并设置工作状态
 */
function transferEnergy(creep: Creep, target: AnyStoreStructure) {
    creep.transfer(target, RESOURCE_ENERGY)
    creep.memory.working = false
}

/**
 * 设置能量矿危险
 */
function setSourceDanger(creep: Creep, sourceInfo: SourceInfo) {
    if (creep.hits >= creep.hitsMax) return
    sourceInfo.isDanger = true
}

/**
 * 生成 harvester 的体型
 */
export const createHarvesterBody = (room: Room): BodyPartArrayType => {
    const energyCapacityAvailable = room.energyCapacityAvailable
    if (energyCapacityAvailable <= CONTROLLER_ENERGY[2]) {
        return [
            [WORK, 4],
            [CARRY, MOVE],
        ]
    } else if (energyCapacityAvailable < CONTROLLER_ENERGY[4]) {
        return [
            [WORK, 6],
            [CARRY, 1],
            [MOVE, 2],
        ]
    } else if (energyCapacityAvailable < CONTROLLER_ENERGY[6]) {
        return [
            [WORK, 8],
            [CARRY, 2],
            [MOVE, 2],
        ]
    } else if (energyCapacityAvailable < CONTROLLER_ENERGY[7]) {
        if (!isOfficialShard()) {
            return [
                [WORK, 8],
                [CARRY, 2],
                [MOVE, 2],
            ]
        }
        return [
            [WORK, 12],
            [CARRY, 4],
            [MOVE, 3],
        ]
    } else {
        if (!isOfficialShard()) {
            return [
                [WORK, 12],
                [CARRY, 4],
                [MOVE, 3],
            ]
        }
        return [
            [WORK, 20],
            [CARRY, 4],
            [MOVE, 5],
        ]
    }
}
